/***********************************************************************
	filename: 	CEGUIMouseCursor.cpp
	created:	21/2/2004
	author:		Paul D Turner

	purpose:	Implements MouseCursor class
*************************************************************************/

#include "hgeMouseCursor.h"
#include "hgeExceptions.h"
#include "hgeLogger.h"
#include "hgeGuiSystem.h"
#include "hgePathMgr.h"

const String MouseCursor::EventNamespace("MouseCursor");

/*************************************************************************
	Static Data Definitions
*************************************************************************/
// singleton instance pointer
template<> MouseCursor* Singleton<MouseCursor>::ms_Singleton	= 0;


/*************************************************************************
	Event name constants
*************************************************************************/
const String MouseCursor::EventCursorChanged( "CursorChanged" );


/*************************************************************************
	constructor
*************************************************************************/
MouseCursor::MouseCursor(void)
{
    const hgeRect screenArea(Vector2(0, 0),
                          System::getSingleton().getRenderer()->getDisplaySize());

	// mouse defaults to middle of the constrained area
	d_position.d_x = screenArea.getWidth() / 2;
	d_position.d_y = screenArea.getHeight() / 2;

	// default constraint is to whole screen
	setConstraintArea(&screenArea);

	// mouse defaults to visible
	d_visible = true;

    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(this));
	hgeLogger::getSingleton().logEvent(
       "MouseCursor singleton created. " + String(addr_buff));
}


/*************************************************************************
	Destructor
*************************************************************************/
MouseCursor::~MouseCursor(void)
{
    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(this));
	hgeLogger::getSingleton().logEvent(
       "MouseCursor singleton destroyed. " + String(addr_buff));
}


/*************************************************************************
	Set the current mouse cursor image
*************************************************************************/
HCURSOR MouseCursor::getCursor(const String& cursorFile)
{
	HCURSOR hCursor;
	CursorMap::iterator it = d_cursorRes.find( cursorFile );
	if( it == d_cursorRes.end() )
	{
		hCursor = LoadCursorFromFile( hgePathMgr::GetFullPathInType(RES_UI, cursorFile).c_str() );
		if( hCursor )
		{
			d_cursorRes[cursorFile] = hCursor;
		}
	}
	else
		hCursor = it->second;

	return hCursor;
}

///*************************************************************************
//	Draw the mouse cursor
//*************************************************************************/
//void MouseCursor::draw(void) const
//{
//    if (d_visible && d_cursorImage)
//        d_geometry->draw();
//}

/*************************************************************************
	Set the current mouse cursor position
*************************************************************************/
void MouseCursor::setPosition(const Point& position)
{
    d_position = position;
	constrainPosition();
}


/*************************************************************************
	Offset the mouse cursor position by the deltas specified in 'offset'.
*************************************************************************/
void MouseCursor::offsetPosition(const Point& offset)
{
	d_position.d_x += offset.d_x;
	d_position.d_y += offset.d_y;
	constrainPosition();
}


/*************************************************************************
	Checks the mouse cursor position is within the current 'constrain'
	hgeRect and adjusts as required.
*************************************************************************/
void MouseCursor::constrainPosition(void)
{
    hgeRect absarea(getConstraintArea());

	if (d_position.d_x >= absarea.d_right)
		d_position.d_x = absarea.d_right -1;

	if (d_position.d_y >= absarea.d_bottom)
		d_position.d_y = absarea.d_bottom -1;

	if (d_position.d_y < absarea.d_top)
		d_position.d_y = absarea.d_top;

	if (d_position.d_x < absarea.d_left)
		d_position.d_x = absarea.d_left;
}


/*************************************************************************
	Set the area that the mouse cursor is constrained to.
*************************************************************************/
void MouseCursor::setConstraintArea(const hgeRect* area)
{
    const hgeRect renderer_area(Vector2(0, 0),
                          System::getSingleton().getRenderer()->getDisplaySize());

	if (!area)
	{
		d_constraints = renderer_area;
	}
	else
	{
        d_constraints = area->getIntersection(renderer_area);
	}

	constrainPosition();
}

/*************************************************************************
	Set the area that the mouse cursor is constrained to.
*************************************************************************/
hgeRect MouseCursor::getConstraintArea(void) const
{
    return d_constraints;
}

/*************************************************************************
	Return the current mouse cursor position in display resolution
	independant values.
*************************************************************************/
Point MouseCursor::getDisplayIndependantPosition(void) const
{
    Size dsz(System::getSingleton().getRenderer()->getDisplaySize());

    return Point(d_position.d_x / (dsz.d_x - 1.0f),
                 d_position.d_y / (dsz.d_y - 1.0f));
}

//----------------------------------------------------------------------------//
void MouseCursor::notifyDisplaySizeChanged(const Size& new_size)
{
    const hgeRect screenArea(Vector2(0, 0), new_size);

    //// redraw image back into buffer to regenerate geometry at (maybe) new size
    //if (d_cursorImage)
    //{
    //    d_geometry->reset();
    //    d_cursorImage->draw(*d_geometry, Vector2(0, 0), 0);
    //}
}

//----------------------------------------------------------------------------//


//////////////////////////////////////////////////////////////////////////
/*************************************************************************

	Begin event triggers section

*************************************************************************/
//////////////////////////////////////////////////////////////////////////

void MouseCursor::onCursorChanged(MouseCursorEventArgs& e)
{
	fireEvent(EventCursorChanged, e, EventNamespace);
}


MouseCursor& MouseCursor::getSingleton(void)
{
	return Singleton<MouseCursor>::getSingleton();
}


MouseCursor* MouseCursor::getSingletonPtr(void)
{
	return Singleton<MouseCursor>::getSingletonPtr();
}